/*
 * Copyright 2007 - The JDPF Project Team (http://www.jdpf.org) 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */
package org.jdpf.core.netvalidator;

import java.util.ArrayList;
import java.util.List;

import org.jdpf.core.kernel.elements.Place;
import org.jdpf.core.kernel.elements.Token;
import org.jdpf.core.kernel.exceptions.CoreException;
import org.jdpf.core.kernel.exceptions.CoreExceptionsEnum;
import org.jdpf.core.kernel.execution.NetValidatorExecutor;
import org.jdpf.core.kernel.logging.ILogger;
import org.jdpf.core.kernel.logging.LoggerFactory;
import org.jdpf.core.plugins.datatypes.AbstractDataType;
import org.jdpf.core.plugins.datatypes.OutputDataTypesListDataType;

/**
 * This performs the dynamic net validations. The component
 * is going to be fired with a dummy token with the goal of 
 * checking if input/output data types of the connected blocks
 * are matching.
 * 
 * @author Paolo Ciccarese, Cristiana Larizza, Bruno Farina, Paolo Mauri
 */
public class DynamicNetValidator {
	
	private static final ILogger logger=LoggerFactory.getDefault().getLogger();
		
	public void validateNetDynamically(NetValidatorExecutor netExecutor) throws CoreException {
		if(netExecutor.getNet().isValid())
			checkDatatypeValidation(netExecutor);
			checkConnections(netExecutor);
	}
	
	private void checkConnections(NetValidatorExecutor netExecutor) throws CoreException {
		int countStartPlaces = 0;
		int countTokensInEndPlaces = 0;
		for(Place p:netExecutor.getNet().getAllPlaces()){
			if(p.isStartPlace()){
				countStartPlaces++;
			}
			
			if(p.isEndPlace()){
				countTokensInEndPlaces+=p.getTokens().size();	
			}
			p.removeToken();
		}
		
		logger.log("Start Places count: " + countStartPlaces + " - Tokens in End Places count: " + countTokensInEndPlaces);
		if(countTokensInEndPlaces < countStartPlaces){
			throw new CoreException(CoreExceptionsEnum.BadWiring, "Detected Start Places not connected to an End Place");
		}
	}

	private void checkDatatypeValidation(NetValidatorExecutor netExecutor) throws CoreException {
		Token t = new Token(); // Dummy token
		List<AbstractDataType> in = new ArrayList<AbstractDataType>(2);
		OutputDataTypesListDataType out = new OutputDataTypesListDataType();
		out.putDataType("none");
		in.add(out);
		t.setValueList(in);
		for (Place p : netExecutor.getNet().getStartPlaces()) {
			p.addToken(t);
		}
		
		try {
			netExecutor.process();
		} catch (CoreException e){
			throw e;
		}
		catch (Exception e) {
			throw new CoreException(CoreExceptionsEnum.Unknown, e.getMessage());
		}
		
		//Tokens removed from Places in checkConnections() method 
	}
}